import re

from django.shortcuts import render, get_object_or_404, redirect, reverse
from django.contrib.auth.decorators import login_required
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth import get_user_model
import markdown
from bs4 import BeautifulSoup

from .models import History, Notice, Advice, Progress


class NoParagraphExtension(markdown.Extension):
    def extendMarkdown(self, md_):
        md_.preprocessors.register(NoParagraphPreprocessor(md_), 'noparagraph', 175)


class NoParagraphPreprocessor(markdown.preprocessors.Preprocessor):
    def run(self, lines):
        new_lines = []
        for line in lines:
            new_lines.append(line.replace('\r', '<br>'))
        return new_lines


md = markdown.Markdown(extensions=[NoParagraphExtension()])


def safe_text(text: str):
    text = re.sub(r'\s*on\w+\s*=\s*"[^"]*"\s*', '', text)
    soup = BeautifulSoup(text, 'html.parser')
    soup = BeautifulSoup(soup.prettify(), 'html.parser')
    banned_elements = [
        'script',
        'div',
    ]
    for banned_element in banned_elements:
        tags = soup.find_all(banned_element)
        for tag in tags:
            tag.extract()
    return str(soup).strip()


def text_to_markdown(text: str):
    return md.convert(safe_text(text))


def text_to_markdown_without_p(text: str):
    return text_to_markdown(text).removeprefix('<p>').removesuffix('</p>')


@login_required
def index(request):
    notices = []
    for notice in Notice.objects.all():
        notices.append({
            'time': notice.time,
            'title': text_to_markdown_without_p(notice.title),
            'content': text_to_markdown_without_p(notice.content),
        })
    context = {
        'notices': notices,
        'page_index': True,
        'processes': Progress.objects.all(),
    }
    return render(request, 'main/index.html', context=context)


def get_believers():
    return get_user_model().objects.filter(identity__isnull=False)


@login_required
def believers(request):
    context = {
        'page_believers': True,
        'believers': get_believers(),
    }
    return render(request, 'main/believers.html', context=context)


@login_required
def believer(request, believer_id):
    if request.user.id == believer_id:
        believer_obj = request.user
    else:
        believer_obj = get_object_or_404(get_believers(), id=believer_id)
    context = {
        'believer': believer_obj,
        'origin_homepage': believer_obj.homepage,
        'homepage': text_to_markdown_without_p(believer_obj.homepage),
    }
    return render(request, 'main/believer.html', context=context)


@login_required
def history(request):
    if History.objects.exists():
        first_obj = History.objects.first()
        last_obj = History.objects.last()
        history_number = request.GET.get('number', first_obj.number)
        history_obj = get_object_or_404(History, number=history_number)

        class NullHistory:
            def __init__(self, number):
                self.number = number

        previous_obj = History.objects.filter(number__lt=history_obj.number).last()
        has_previous = True
        if previous_obj is None:
            previous_obj = NullHistory(first_obj.number)
            has_previous = False
        next_obj = History.objects.filter(number__gt=history_obj.number).first()
        has_next = True
        if next_obj is None:
            next_obj = NullHistory(last_obj.number)
            has_next = False
        history_ = {
            'number': history_obj.number,
            'display': text_to_markdown_without_p(history_obj.__str__()),
            'content': text_to_markdown_without_p(history_obj.content),
        }
        histories = History.objects.all()
        histories_ = []
        for part in histories:
            histories_.append({
                'number': part.number,
                'display': text_to_markdown_without_p(part.__str__())
            })
        context = {
            'page_history': True,
            'history': history_,
            'previous': previous_obj,
            'next': next_obj,
            'has_previous': has_previous,
            'has_next': has_next,
            'first': first_obj,
            'last': last_obj,
            'histories': histories_,
        }
    else:
        context = {}
    return render(request, 'main/history.html', context=context)


@login_required
def advise(request):
    all_advice = Advice.objects.all()
    finished_advice = all_advice.filter(finished=True)
    unfinished_advice = all_advice.filter(finished=False)
    if request.method == 'POST':
        data = request.POST
        title = data.get('title', '').strip()
        content = data.get('content', '').strip()
        if not (len(title) > 200 or title == '' or content == '' or request.user.identity is None):
            Advice.objects.create(title=title, content=content, sender=request.user, finished=False)
    context = {
        'page_advise': True,
        'finished_advice': finished_advice,
        'unfinished_advice': unfinished_advice,
    }
    return render(request, 'main/advise.html', context=context)


@login_required
def animation(request):
    return render(request, 'main/animation.html')


@staff_member_required
def advise_tick(request, advice_id):
    advice = get_object_or_404(Advice, id=advice_id)
    advice.finished = not advice.finished
    advice.save()
    return redirect(reverse('main:advise'))
